/*  WiFi softAP Example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_mac.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"

#include "lwip/err.h"
#include "lwip/sys.h"

#define             MODE            0                           //1：表示WIFI STA模式， 0：表示WIFI AP模式

/* The examples use WiFi configuration that you can set via project configuration menu.

   If you'd rather not, just change the below entries to strings with
   the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid"
*/
#if MODE
#define STA_WIFI_SSID      "HUAWEI-sky"
#define STA_WIFI_PASS      "gz20230109"

#define ESP_MAXIMUM_RETRY          5                        //最大重连次数
/* The event group allows multiple bits for each event, but we only care about two events:
 * - we are connected to the AP with an IP
 * - we failed to connect after the maximum amount of retries */
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT      BIT1

/* FreeRTOS event group to signal when we are connected*/
static EventGroupHandle_t wifi_event_group;
static const char *TAG = "wifi_STA";
uint8_t conn_retry_num = 0;                                 //尝试重连次数
#else

#define AP_WIFI_SSID        "ESP32S3_WifiDemo"
#define AP_WIFI_PASS        "qwer1234"

#define AP_WIFI_CHANNEL         1
#define AP_WIFI_MAX_STA_CONN    5

static const char *TAG = "wifi_AP";

#endif
static void wifi_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data)
{
#if MODE
    if(event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START)                    //WIFI作为STA模式启动
    {
        esp_wifi_connect();                                                            //连接WIFI
    }else if((event_base == WIFI_EVENT)&&(event_id == WIFI_EVENT_STA_DISCONNECTED))    //wifi断开连接事件
    {
        if(conn_retry_num < ESP_MAXIMUM_RETRY)
        {
            esp_wifi_connect();
            conn_retry_num++;
            ESP_LOGI(TAG, "retry to connect to the AP");
        }else{
            xEventGroupSetBits(wifi_event_group, WIFI_FAIL_BIT);
        }
        ESP_LOGI(TAG,"connect to the AP fail");
    }else if ((event_base == IP_EVENT) && (event_id == IP_EVENT_STA_GOT_IP)) 
    {
        ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
        ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
        conn_retry_num = 0;
        xEventGroupSetBits(wifi_event_group, WIFI_CONNECTED_BIT);
    }
#else
    if (event_id == WIFI_EVENT_AP_STACONNECTED) 
    {
        wifi_event_ap_staconnected_t* event = (wifi_event_ap_staconnected_t*) event_data;
        ESP_LOGI(TAG, "station "MACSTR" join, AID=%d",
                 MAC2STR(event->mac), event->aid);
    } else if (event_id == WIFI_EVENT_AP_STADISCONNECTED) 
    {
        wifi_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*) event_data;
        ESP_LOGI(TAG, "station "MACSTR" leave, AID=%d",
                 MAC2STR(event->mac), event->aid);
    }
#endif
}

#if MODE

void wifi_init_sta(void)
{
    wifi_event_group = xEventGroupCreate();                             //创建事件组，用于在任务间同步wifi连接状态

    ESP_ERROR_CHECK(esp_netif_init());                                  //初始化底层TCP/IP协议栈

    ESP_ERROR_CHECK(esp_event_loop_create_default());                   //创建默认事件循环，用于处理系统事件
    esp_netif_create_default_wifi_sta();                                //创建默认的Wifi STA网络接口

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();                //获取wifi初始化默认配置
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));                               //初始化wifi驱动

    esp_event_handler_instance_t instance_any_id;
    esp_event_handler_instance_t instance_got_ip;
    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
                                                        ESP_EVENT_ANY_ID,
                                                        &wifi_event_handler,
                                                        NULL,
                                                        &instance_any_id));         //注册wifi事件处理函数，监听所有wifi事件
    ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
                                                        IP_EVENT_STA_GOT_IP,
                                                        &wifi_event_handler,
                                                        NULL,
                                                        &instance_got_ip));         //注册IP事件处理函数，专门监听获取IP地址事件

    wifi_config_t wifi_config = {
        .sta = {
            .ssid = STA_WIFI_SSID,                              //要连接的WiFi 的SSID
            .password = STA_WIFI_PASS,                          //要连接的wifi密码
            /* 认证模式阈值：如果密码符合WPA2标准（密码长度>=8），则默认重置为WPA2
             * 如果要连接到已弃用的WEP/WPA网络，请将阈值设置为WIFI_AUTH_WEP/WIFI_AUTH_WPA_PSK
             * 并设置符合WIFI_AUTH_WEP/WIFI_AUTH_WPA_PSK标准的密码长度和格式
             */
            .threshold.authmode = WIFI_AUTH_WPA2_PSK,                   //
            .sae_pwe_h2e = WPA3_SAE_PWE_UNSPECIFIED,
            .sae_h2e_identifier = "",
        },
    };
    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
    ESP_ERROR_CHECK(esp_wifi_start() );

    ESP_LOGI(TAG, "wifi_init_sta finished.");

    /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum
     * number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */
    EventBits_t bits = xEventGroupWaitBits(wifi_event_group,
            WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
            pdFALSE,
            pdFALSE,
            portMAX_DELAY);

    /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually
     * happened. */
    if (bits & WIFI_CONNECTED_BIT) {
        ESP_LOGI(TAG, "connected to ap SSID:%s password:%s",
                 STA_WIFI_SSID, STA_WIFI_PASS);
    } else if (bits & WIFI_FAIL_BIT) {
        ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s",
                 STA_WIFI_SSID, STA_WIFI_PASS);
    } else {
        ESP_LOGE(TAG, "UNEXPECTED EVENT");
    }
}

#else

void wifi_init_softap(void)
{
    ESP_ERROR_CHECK(esp_netif_init());          //初始化底层TCP/IP协议栈
    ESP_ERROR_CHECK(esp_event_loop_create_default());   //创建默认事件循环，用于处理系统事件
    esp_netif_create_default_wifi_ap();                 //创建默认的wifi AP网络接口

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();    //获取wifi初始化默认配置
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));                   //初始化Wifi驱动

    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
                                                        ESP_EVENT_ANY_ID,
                                                        &wifi_event_handler,
                                                        NULL,
                                                        NULL));             //注册Wifi事件处理函数，监听所有wifi事件

    wifi_config_t wifi_config = {
        .ap = {
            .ssid = AP_WIFI_SSID,                                           //设置AP的SSID名称
            .ssid_len = strlen(AP_WIFI_SSID),                               //计算SSID长度
            .channel = AP_WIFI_CHANNEL,                                     //设置wifi信道
            .password = AP_WIFI_PASS,                                       //设置连接密码
            .max_connection = AP_WIFI_MAX_STA_CONN,                         //设置最大客户端连接数
            .authmode = WIFI_AUTH_WPA2_PSK,                                 //设置认证模式为wpa2
            .pmf_cfg = {
                    .required = true,                                       //启用保护管理帧（安全特性）
            },
        },
    };
    if (strlen(AP_WIFI_PASS) == 0) {
        wifi_config.ap.authmode = WIFI_AUTH_OPEN;                           //若密码字符串为空，则使用开放模式(无需密码)
    }

    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));                       //设置wifi工作模式为AP模式
    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config));         //启用AP配置
    ESP_ERROR_CHECK(esp_wifi_start());                                      //启动wifi

    ESP_LOGI(TAG, "wifi_init_softap finished. SSID:%s password:%s channel:%d",
             AP_WIFI_SSID, AP_WIFI_PASS, AP_WIFI_CHANNEL);
}

#endif

void app_main(void)
{
    //Initialize NVS
    esp_err_t ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
      ESP_ERROR_CHECK(nvs_flash_erase());
      ret = nvs_flash_init();
    }
    ESP_ERROR_CHECK(ret);
#if MODE
    ESP_LOGI(TAG, "ESP_WIFI_MODE_STA");
    wifi_init_sta();
#else
    ESP_LOGI(TAG, "ESP_WIFI_MODE_AP");
    wifi_init_softap();
#endif

}
